//
// Created by sgyt on 2020/6/3.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

void print_flgas(struct addrinfo *pAddrinfo);

void print_family(struct addrinfo *pAddrinfo);

void print_type(struct addrinfo *pAddrinfo);

void print_protocol(struct addrinfo *pAddrinfo);

int main(int argc, char *argv[])
{
    struct addrinfo *ailist,*aip;

    char *addr;
    struct sockaddr_in *sinp;
    struct addrinfo hint;
    char abuf[INET_ADDRSTRLEN];

    int res;

    hint.ai_flags = AI_CANONNAME;
    hint.ai_family = 0;
    hint.ai_socktype = 0;
    hint.ai_protocol = 0;
    hint.ai_addrlen = NULL;
    hint.ai_addr = NULL;
    hint.ai_canonname = NULL;
    hint.ai_next = NULL;

    res = getaddrinfo("harry","nfc",&hint,&ailist);
    if(res != 0)
    {
        perror("getaddrinfo is error\n");
        exit(EXIT_FAILURE);
    }

    for(aip = ailist;ailist;aip = ailist->ai_next)
    {
        print_flgas(aip);
        print_family(aip);
        print_type(aip);
        print_protocol(aip);
        printf("\n\thost %s\n",aip->ai_canonname?aip->ai_canonname:"-");

        if(aip->ai_family == AF_INET)
        {
            sinp = (struct sockaddr_in *)aip->ai_addr;
            addr = inet_ntop(AF_INET,&sinp->sin_addr,abuf,INET_ADDRSTRLEN);
            printf("address %s\n",addr?addr:"unkown");
            printf("port %d\n",ntohs(sinp->sin_port));
        }

        printf("\n");
    }

    return 0;
}

void print_protocol(struct addrinfo *pAddrinfo) {
    printf(" protocol");
    switch (pAddrinfo->ai_protocol){
        case 0:
            printf("default");
            break;
        case IPPROTO_TCP:
            printf("TCP");
            break;
        case IPPROTO_UDP:
            printf("UDP");
            break;
        case IPPROTO_RAW:
            printf("RAW");
            break;
        default:
            printf("unknow %d",pAddrinfo->ai_protocol);

    }
}

void print_type(struct addrinfo *pAddrinfo) {
    printf("type ");
    switch (pAddrinfo->ai_socktype)
    {
        case SOCK_STREAM:
            printf("stream");
            break;
        case SOCK_DGRAM:
            printf("datagram");
            break;
        case SOCK_SEQPACKET:
            printf("seqpacket");
            break;
        case SOCK_RAW:
            printf("raw");
            break;
        default:
            printf("%d",pAddrinfo->ai_socktype);
    }
}

void print_family(struct addrinfo *pAddrinfo) {
    printf("family ");
    switch (pAddrinfo->ai_family)
    {
        case AF_INET:
            printf("inet");
            break;
        case AF_INET6:
            printf("inet6");
            break;
        case AF_UNIX:
            printf("unix");
            break;
        case AF_UNSPEC:
            printf("unspec");
            break;
        default:
            printf("unknow");
    }
}

void print_flgas(struct addrinfo *pAddrinfo) {
    printf("flags");
    if(pAddrinfo->ai_flags == 0)
    {
        printf("0");
    }else{
        if(pAddrinfo->ai_flags & AI_PASSIVE)
        {
            printf("passive");
        }else if(pAddrinfo->ai_flags & AI_CANONNAME)
        {
            printf("canonname");
        }else if(pAddrinfo->ai_flags & AI_NUMERICHOST)
        {
            printf("numerichost");
        }else if(pAddrinfo->ai_flags & AI_V4MAPPED)
        {
            printf("v4mapped");
        }else if(pAddrinfo->ai_flags & AI_ALL)
        {
            printf("all");
        }
    }
}

